/*
 *  ATrackGroup.cpp
 *  libavid
 *
 *  Created by Peter on 24.02.12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */

#include "ATrackGroup.h"
#include "AStream.h"

A_IMPLEMENT_CLASS( 'TRKG', ATrackGroup, AComponent );

void ATrackGroup::readFromStream( AStream& str, const AObjDoc& objd )
{
	AComponent::readFromStream( str, objd );
	
	TR_TRACE( "Reading ATrackGroup starting at offset " << str.getPos() ); 
	
	UInt8 tagMark, version, minorVersion;
	str.readPod( tagMark );
	str.readPod( version );
	TR_ASSERT( tagMark == 0x02 );
	TR_ASSERT( version == 0x08 );
	
	// tag and version are correct, from then on it's weird
	
	str.readPod( _mode );
	str.readPod( _groupLength );
	str.readPod( _numScalars );
	
	Int32 numTracks;
	str.readPod( numTracks );
	
	TR_ASSERT( numTracks >= 0 );
	
	//dump( std::clog );
	
	TR_TRACE( "ATrackGroup: Reading " << numTracks << " Tracks, starting at offset " << str.getPos() << "..." );
	
	for( int i = 0; i < numTracks; ++i )
	{
		// FIXME: Not exception safe, we could leak Track
		Track* track = new Track;
		
		str.readPod( track->_optFlags );
		str.readPod( track->_labelNumber );
		
		// Also sighted: _optFlags == 49, but no special code required
		// Also sighted: 13
		
		// 519s (sequences only and rare) have additional attributes
		if( track->_optFlags == 519 || track->_optFlags == 527 )
			str.skip( 4 ); // ulong/ATTR-pointer
		
		// 517 happens in sequences ('CMPO') a lot (not sighted anywhere else), 
		// Same for 541, but not nearly as often. There is only an occasional 514 mixed with regular 517s.
		// 519 in Sequences only and rare, too.
		if( track->_optFlags == 517 || track->_optFlags == 519 || track->_optFlags == 527 || track->_optFlags == 541 || track->_optFlags == 533 )
			str.skip( 4 ); // SessionAttrs (ulong/object pointer) TODO: Store
		
		str.readPod( track->_trackComponent ); // TODO: Resolve to a pointer via AObjDoc
		
		if( track->_optFlags == 541 || track->_optFlags == 525 || track->_optFlags == 527 || track->_optFlags == 13 ) // 13 comes up in ATrackEffect
			str.skip( 4 ); // ulong OMFI:TRAK:FillerProxy // TODO: STore (object reference)
		
		if( track->_optFlags == 541 || track->_optFlags == 525 || track->_optFlags == 533 ) {
			UInt32 bobObj;
			str.readPod( bobObj );// ulong __OMFI:TRAK:Bob (object pointer to an ATrackRef it seems) TODO: Store
			TR_TRACE( "ATrackGroup: BOB reference is to object #" << bobObj << " in the AObjDoc" );
		}
		
		_tracks.push_back( track );
	}
	
	TR_TRACE( "ATrackGroup: Read tracks, now at offset " << str.getPos() << "." );
	
	// Read data of PCLass Extension LockNumber
	str.readPod( tagMark );
	str.readPod( minorVersion );
	
	// This means we made probably came across a set of OptFlags value for a 
	// track we didn't know how to handle. We are going to assert shortly 
	// thereafter on the TagMark check, so we want to know as much as possible
	// about the object we were reading when it happened.
	if( tagMark != 0x01 )
		dump( std::clog );
	
	// An assertion here probably means there is a set of OptFlags for tracks
	// we are not yet aware of and thus not handling correctly.
	TR_ASSERT( tagMark == 0x01 );
	TR_ASSERT( minorVersion == 0x01 );
	
	for( int i = 0; i < numTracks; ++i )
	{
		str.readPod( tagMark );
		TR_ASSERT( tagMark == 69 );

		str.readPod( _tracks[ i ]->_lockNumber );
	}
}

#define TRACE_FIELD( x ) "\t" #x ": " << x << std::endl

void ATrackGroup::dump( std::ostream& str ) const
{
	str << "ATrackGroup {" << std::endl;
	str << "\t";
	AComponent::dump( str );
	str << "\t_mode: " << static_cast< int >( _mode ) << std::endl;;
	str << TRACE_FIELD( _groupLength );
	str << TRACE_FIELD( _numScalars );
	str << "\t_tracks[ " << _tracks.size() << " ] {" << std::endl;
	
	TrackList::const_iterator it = _tracks.begin();
		
	for( int i = 0; it != _tracks.end(); ++it, ++i ) {
		str << "\t\tTrack #" << i << " {" << std::endl;
		
		str << "\t\t\t_optFlags: " << (*it)->_optFlags << std::endl;
		str << "\t\t\t_labelNumber: " << (*it)->_optFlags << std::endl;
		str << "\t\t\t_trackComponent: " << (*it)->_trackComponent << std::endl;
		str << "\t\t\t_lockNumber: " << (*it)->_lockNumber << std::endl;
		
		str << "\t\t}" << std::endl;
	}
	
	str << "\t}" << std::endl;
	str << "}" << std::endl;
}